/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package desktopapplication1;

/**
 *
 * @author Ludger
 */

import java.util.Iterator;

/**
 *
 * @author Ludger
 */
public class Queue <T>{
    protected int size;
    protected Node top;
    protected Node bottom;
    /**
     * Node Class
     * This class holds each nodes information
     */
    protected  class Node
    {
        private T data;
        private Node next;
        /**
         * This constructor is to create a new node with the following information:
         * @param data 
         * @param next 
         */
        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
        /**
         * This constructor is when you need to set data only
         * @param data 
         */
        public Node(T data)
        {
            this.data = data;
            this.next = null;
        }
        /**
         * this sets both variables to null
         */
        public Node() {
            this.data = null;
            this.next = null;
        }
    }
    /**
     * this is the constructor that sets all the initial values
     */
    public Queue()
    {
        size = 0;
        top = null;
        bottom = null;
    }
    /**
     * this is to check if the queue is empty
     * @return returns true if its empty or false if its not
     */
    public boolean isEmpty()
    {
        return top == null;
    }
    /**
     * this checks the size of the current queue
     * @return int value thats the size
     */
    public int size()
    {
        return size;
    }
    /**
     * returns the next value but does not take it off the queue
     * @return the next data
     */
    public T peek()
    {
        if(isEmpty()) throw new RuntimeException("No datas in queue");
        return top.data;
    }
    /**
     * adds a new data to the queue
     * @param data puts it at the end of the queue
     */
    public void enqueue(T data)
    {
        Node temp = new Node(data);
        if(isEmpty())
        {
            top = temp;
            bottom = temp;
        }else 
        {
            bottom.next = temp;
            bottom = temp;
        }
        size++;
    }
    /**
     * removes the data and the front of the queue and returns it
     * @return the next data in queue and removes it from there.
     */
    public T dequeue()
    {
        if(isEmpty()) throw new RuntimeException("No datas in queue");
        T data = top.data;
        top = top.next;
        size--;
        if(isEmpty()) bottom = null;
        return data;
    }
    /**
     * This returns a string version of the queue
     * @return String with spaces between each data
     */
    @Override
    public String toString() 
    {
        if(isEmpty()) throw new RuntimeException("No datas in queue");
        String ret = "";
        Node temp = top;
        ret += temp.data + " ";
        while(temp.next != null)
        {
            temp = temp.next;
            ret += temp.data + " ";
        }
        return ret;
    }
    
    /**
     * Request iterator function.
     * @return returns type Iterator and 
     */
    public Iterator<T> iterator()  {
        return new iteratThis();
    }
    /**
     * This is a Iterator gets returned through iterator(); and helps go though all the elements in the queue.
     */
    protected class iteratThis implements Iterator<T>
    {
        private Node current = top;
        /**
         * Check if there is another data
         * @return type boolean true if there is a data and false if there is not
         */
        public boolean hasNext() {
            return current != null;
        }
        /**
         * Gets the next data
         * @return This returns the next data
         */
        public T next() {
            if(!hasNext()) throw new NullPointerException("The iterator is empty");
            T data = current.data;
            current = current.next;
            return data;
        }
        /**
         * This does not work for a priority queue
         */
        public void remove() {
            throw new UnsupportedOperationException("Not supported.");
        }
        
    }
}